(Zhu et al. 2008) (Xie 2023) (Robinson,
McCarthy, and Smyth 2010) (Morgan
2022) (Durinck et al. 2009) (Gu et al. 2014) (Gu,
Eils, and Schlesner 2016) (Wickham
2016) (Slowikowski 2023) (Raudvere et al. 2019)
if (!requireNamespace("GEOmetadb", quietly = TRUE))
BiocManager::install("GEOmetadb")
if (!requireNamespace("knitr", quietly = TRUE))
install.packages("knitr")
if (!require("edgeR", quietly = TRUE))
BiocManager::install("edgeR")
if (!requireNamespace("BiocManager", quietly = TRUE))
install.packages("BiocManager")
if (!requireNamespace("biomaRt", quietly = TRUE))
BiocManager::install("biomaRt")
if (!requireNamespace("ComplexHeatmap", quietly = TRUE))
BiocManager::install("ComplexHeatmap")
if (!requireNamespace("circlize", quietly = TRUE))
BiocManager::install("circlize")
if (!requireNamespace("ggplot2", quietly = TRUE))
install.packages("ggplot2")
if (!requireNamespace("ggrepel", quietly = TRUE))
install.packages("ggrepel")
Calling required packages
library(BiocManager)
library(GEOmetadb)
library(knitr)
library(edgeR)
library(biomaRt)
library(ComplexHeatmap)
library(circlize)
library(ggplot2)
library(ggrepel)
Download the data
GSE152074 raw data supplemntary file downloaded
sfiles = getGEOSuppFiles('GSE152075')
fnames = rownames(sfiles)
# there is only one supplemental file
readData = read.table(fnames[1],header=TRUE, check.names = TRUE)
Data
Data from (Lieberman et al. 2020).
kable(readData[1:5, 1:5], type = "html", row.names = TRUE)
Table 1: Original data contains HGNC annotation as row names. Column
names have prefixes before their identifier number as either POS or NEG.
Corresponding to either positive for COVID19 or negative.
Assess
Add 1 to all values of data so later on when conducting log2(cpm) we
can avoid negative infinity values. (Advised by Professor Isserlin)
readData <- readData + 1
Setting first column as gene id for future format purposes
#Place rownames in first column for future format purposes
inter <- data.frame("HUGO" = rownames(readData))
geneData <- cbind(inter$HUGO, readData)
colnames(geneData)[1] <- "HUGO"
Clean
Remove any outliers that does not have at least 2 read per million in
n of the samples. We set this as 2 since we add 1 to all of our dataset
in the beginning of the code to have better plots. Denoting n as the
smallest group of replicates which is the control group of 53. Using n =
53 conduct the removal of low counts.
#translate out counts into counts per millison using
#the edgeR package function cpm
cpms = cpm(geneData[,2:485])
rownames(cpms) <- geneData[,1]
# get rid of low counts
keep = rowSums(cpms >2) >=53
geneData_exp_filtered = geneData[keep,]
Remove version numbers if they exists on gene id(HUGO) column. This
makes it easier for mapping later on.
geneData_exp_filtered[,1] <- gsub("\\.[0-9]", "", geneData_exp_filtered[,1])
Map
#Mapping the name using biomatr
# list available gene annotation databases
bio <- useMart("ensembl", dataset = "hsapiens_gene_ensembl")
conversion_stash <- "geneMapping.rds"
if(file.exists(conversion_stash)){
geneMapping <- readRDS(conversion_stash)
} else{
# convert column of gene IDs to Hugo symbols
geneMapping <- getBM(attributes = c("ensembl_gene_id", "hgnc_symbol"),
mart = bio,
filters = "hgnc_symbol",
values = geneData_exp_filtered[,1])
saveRDS(geneMapping, conversion_stash)
}
Combine the mapped gene data to original data
#Merge the data
mergedData <- merge(geneData_exp_filtered, geneMapping, by.x = 1, by.y = 2)
#remove duplicate rows in the gene data
mergedDataNoDup <- mergedData[!duplicated(mergedData[,1:485]),]
Apply Normalization
Randomly sample data to reduce the size of sample. Original sample is
too large leading to computation errors due to the limitation of
author’s computer.
set.seed(12345)
randomSamplePOS <- sample(mergedDataNoDup[2:431], 25)
randomSampleNEG <- sample(mergedDataNoDup[432:485], 25)
randomSample <- cbind(randomSamplePOS,randomSampleNEG, mergedDataNoDup$ensembl_gene_id, mergedDataNoDup$HUGO)
Define groups to use in normalization
samples <- data.frame(lapply(colnames(randomSample[1:50]),
FUN=function(x){unlist(strsplit(x,
split = "_"))[c(2,1)]}))
colnames(samples) <- colnames(randomSample[1:50])
rownames(samples) <- c("patients","cell_type")
samples <- data.frame(t(samples))
Applying TMM to data
filtered_data_matrix <- as.matrix(randomSample[1:50])
rownames(filtered_data_matrix) <- randomSample$`mergedDataNoDup$ensembl_gene_id`
d = DGEList(counts=filtered_data_matrix, group=samples$cell_type)
d = calcNormFactors(d)
normalized_counts <- cpm(d)
#add columns of ensembl and hgnc id
normalized_count_data = data.frame(normalized_counts)
normalized_count_data$ensembl_gene_id <- mergedDataNoDup$ensembl_gene_id
normalized_count_data$hgnc_symbol <- mergedDataNoDup$HUGO
#This is a duplicate ensembl id that is giving errors when running code.
normalized_count_data <- normalized_count_data[-c(1902),]
model_design <- model.matrix(~samples$cell_type+0)
d <- estimateDisp(d, model_design)
Differential Gene Expression
LIMMA
p-value calculation using LIMMA
model_design <- model.matrix(~ samples$cell_type )
expressionMatrix <- as.matrix(normalized_count_data[,1:50])
rownames(expressionMatrix) <-
normalized_count_data$ensembl_gene_id
colnames(expressionMatrix) <-
colnames(normalized_count_data)[1:50]
minimalSet <- ExpressionSet(assayData=expressionMatrix)
Taking into account Patient variability
model_design_pat <- model.matrix(
~ samples$patients + samples$cell_type)
fit_pat <- lmFit(minimalSet, model_design_pat)
fit2_pat <- eBayes(fit_pat,trend=TRUE)
topfit_pat <- topTable(fit2_pat,
coef=ncol(model_design_pat),
adjust.method = "BH",
number = nrow(expressionMatrix))
#merge hgnc names to topfit table
output_hits_pat <- merge(normalized_count_data[,51:52],
topfit_pat,by.y=0,by.x=1,all.y=TRUE)
#sort by pvalue
output_hits_pat <- output_hits_pat[order(output_hits_pat$P.Value),]
length(which(output_hits_pat$P.Value < 0.05))
length(which(output_hits_pat$adj.P.Val < 0.05))
QLF
d = DGEList(counts=filtered_data_matrix, group=samples$cell_type)
d <- estimateDisp(d, model_design_pat)
fit <- glmQLFit(d, model_design_pat)
qlf.pos_vs_neg <- glmQLFTest(fit, coef='samples$cell_typePOS')
kable(topTags(qlf.pos_vs_neg), type="html",row.names = FALSE)
P-values were corrected using Quasilikelihood method. Quasilikelihood
is better becacuse it is tailored towards RNAseq data
qlf_output_hits <- topTags(qlf.pos_vs_neg,sort.by = "PValue",
n = nrow(normalized_count_data))
length(which(qlf_output_hits$table$PValue < 0.05))
length(which(qlf_output_hits$table$FDR < 0.05))
Thresholded over-representation analysis
Write to file upregulated, and downregulated genes
Which ones are upregulated and downregulated
length(which(qlf_output_hits$table$PValue < 0.05
& qlf_output_hits$table$logFC > 0))
length(which(qlf_output_hits$table$PValue < 0.05
& qlf_output_hits$table$logFC < 0))
qlf_output_hits_withgn <- merge(randomSample[,51:52],qlf_output_hits, by.x=1, by.y = 0)
#number higher the lower the pvalue, and if it is upregulated number is positive, and negative for downregulated
qlf_output_hits_withgn[,"rank"] <- -log(qlf_output_hits_withgn$PValue,base =10) * sign(qlf_output_hits_withgn$logFC)
qlf_output_hits_withgn <- qlf_output_hits_withgn[order(qlf_output_hits_withgn$rank),]
upregulated_genes <- qlf_output_hits_withgn$`mergedDataNoDup$HUGO`[
which(qlf_output_hits_withgn$PValue < 0.05
& qlf_output_hits_withgn$logFC > 0)]
downregulated_genes <- qlf_output_hits_withgn$`mergedDataNoDup$HUGO`[
which(qlf_output_hits_withgn$PValue < 0.05
& qlf_output_hits_withgn$logFC < 0)]
write.table(x=upregulated_genes,
file=file.path("data","upregulated_genes.txt"),sep = "\t",
row.names = FALSE,col.names = FALSE,quote = FALSE)
write.table(x=downregulated_genes,
file=file.path("data","downregulated_genes.txt"),sep = "\t",
row.names = FALSE,col.names = FALSE,quote = FALSE)
write.table(x=data.frame(genename= qlf_output_hits_withgn$`mergedDataNoDup$HUGO`,F_stat= qlf_output_hits_withgn$rank),
file=file.path("data","ranked_genelist.txt"),sep = "\t",
row.names = FALSE,col.names = FALSE,quote = FALSE)
Non-thresholded Gene set Enrichment Analysis
gmt_url = "http://download.baderlab.org/EM_Genesets/current_release/Human/symbol/"
# list all the files on the server
filenames = RCurl::getURL(gmt_url)
tc = textConnection(filenames)
contents = readLines(tc)
close(tc)
# get the gmt that has all the pathways and does not include terms inferred
# from electronic annotations(IEA) start with gmt file that has pathways only
rx = gregexpr("(?<=<a href=\")(.*.GOBP_AllPathways_no_GO_iea.*.)(.gmt)(?=\">)", contents,
perl = TRUE)
gmt_file = unlist(regmatches(contents, rx))
dest_gmt_file <- file.path(data_dir, gmt_file)
download.file(paste(gmt_url, gmt_file, sep = ""), "bader_lab.gmt")
Conduct non-thresholded gene set enrichment analysis using the ranked
set of genes from Assignment #2.
- What method did you use? What genesets did you use? Make sure to
specify versions and cite your methods. I used the GSEA desktop
application to run GSEA Subramanian, Tamayo, et al. (2005, PNAS) and
Mootha, Lindgren, et al. (2003, Nature Genetics). I used the genesets
from the bader lab extracted from the code above I used. Or it can be
retrieved from here http://download.baderlab.org/EM_Genesets/current_release/Human/symbol/.
- Summarize your enrichment results. SARs-CoV-2 positive samples: 4965
/ 6074 gene sets are upregulated in phenotype na_pos 442 gene sets are
significant at FDR < 25% 410 gene sets are significantly enriched at
nominal pvalue < 1% 662 gene sets are significantly enriched at
nominal pvalue < 5% Top gene-set:
HALLMARK_INTERFERON_ALPHA_RESPONSE%MSIGDBHALLMARK%HALLMARK_INTERFERON_ALPHA_RESPONSE
Number of genes in leading edge: 80 Top gene associated: CXCL11
SARs-CoV-2 negative samples: 1109 / 6074 gene sets are upregulated in
phenotype na_neg 274 gene sets are significantly enriched at FDR <
25% 196 gene sets are significantly enriched at nominal pvalue < 1%
276 gene sets are significantly enriched at nominal pvalue < 5% Top
gene-set: ENERGY DERIVATION BY OXIDATION OF ORGANIC COMPOUNDS%GOBP%GO:0015980 Number of genes in leading
edge: 165 Top gene associated: TEFM 3. How do these results compare to
the results from the thresholded analysis in Assignment #2. Compare
qualitatively. Is this a straight forward comparison? Why or why not?
For the upregulated genes the top results are negative regulation of
viral genome replication, negative regulation of viral process, response
to type II interferon. downregulated we got cytoplasmic translation,
positive regulation of respiratory burst, and intermediate
filament-based process. I had too many genes so I couldn’t run all the
genes at once for my whole list. For upregulated in thresholded and
non-thresholded they align a bit together by having interferon related
pathway results. Other then that they don’t seem to be similar. A common
pathway in downregulated and and all of the genes for thresholded was a
pathway related to cytoplasmic. However in non thresholded there were
cytoplasmic related pathways but were very low in the list. It is not a
straight forward comparison they both have different values as analysis.
The thresholed could be more sensitive while the non-thresholded be more
general.
Using your results from your non-thresholded gene set enrichment
analysis visualize your results in Cytoscape.
red - upregulated from neg to pos, blue - downregulated in positive
covid19 patietns compared to negative patients. ranked list = depending
on the expression of a gene in pos compared to neg
1.
Create an enrichment map - how many nodes and how many edges in the
resulting map?
379 Nodes 1511 Edges
What thresholds were used to create this map?
FDR q-value cutoff: 0.1 Analysis Type: GSEA Node cutoff: 0.1 Edge
cutoff: 0.375
Make sure to record all thresholds. Include a screenshot of your
network prior to manual layout.
2. Annotate your network - what parameters did you use to annotate
the network. If you are using the default parameters make sure to list
them as well.
Used the auto annotate application in cytoscape. Cluster algorithm:
MCL Cluster Label Column: GS_DESCR Label Algorithm: WordCloud: Adjacent
Words(default) Max words per label: 3 Minimum word occurrence: 1
Adjacent word bonus: 8 Border Width: 3 Opacity: 20% Font Scale: 20%
3. Make a publication ready figure - include this figure with proper
legends in your notebook.
4. Collapse your network to a theme network. What are the major
themes present in this analysis? Do they fit with the model? Are there
any novel pathways or themes?
Major
themes present: Upregulated: - GPCRS Rhodopsin ligand - Chemokine
Migration chemotaxis - Cellular response necrosis - type II interferon -
Migration monocyte chemotaxis - Surface receptor pattern
Downregulated: - gluconeogenesis glycolysis - superpathway warburg
effect - srp protein synthesis
Present your results with the use of tables and screenshots. All
figures should have appropriate figure legends.
If using figures create a figures directory in your repo and make
sure all references to the figures are relative in your Rmarkdown
notebook.
The most important aspect of the analysis is relating your results
back to the initial data and question.
- Do the enrichment results support conclusions or mechanism discussed
in the original paper? How do these results differ from the results you
got from Assignment #2 thresholded methods.
This is a quotation taken from the original paper “SARS-CoV-2 induced
a strong antiviral response with up-regulation of antiviral factors such
as OAS1-3 and IFIT1-3 and T helper type 1 (Th1) chemokines CXCL9/10/11,
as well as a reduction in transcription of ribosomal proteins” (Lieberman et al. 2020). They have found
up-regulation in number of genes. The largest collapsed theme with 729
genes the GPCRS Rhodopsin ligand has two very large pathways named the
GPCR ligand binding, and the CLASS A 1 (RHODOPSIN-LIKE RECEPTORS). Both
of these gene-sets have at the top of their leading edge the CXCL
10/11/13 similar to the paper where they had up-regulation in the CXCL
9/10/11. In this sense the enrichment results support conclusions made
in the original paper. Another example is the chemokine migration
chemotaxis. In this major theme there are gene-sets involved in pathways
such as the response to type II interferon, cellular response to type II
interferon, . In the original paper they mention that as viral load
increased the expression of interferon-responsive genes went up. Both of
the two themes mentioned are up-regulated gene-sets. It seems that the
enrichment results support the conclusion in the original paper.
Comparing from A2 threshold methods in the upregulated analysis for GO
using g:profiler we also had results such as response to type II
interferon, and cellular response to type II interferon. However we do
not see a lot of gene-sets in the up-regulated section for chemokine
related pathways.
For down regulated gene-sets for our network results from GSEA shows
a major theme called srp protein synthesis. In this we have genesets
such as the cytoplasmic translation. This gene-set is the largest
gene-set inside srp protein synthesis and it is also the top result for
down regulated genes gene-set for g:profiler using GO annotation. There
are evident similarities but looking at the rest of the graph each
analysis give results that each other do not have.
- Can you find evidence, i.e. publications, to support some of the
results that you see. How does this evidence support your result? In a
paper they state that SARS-CoV-2 infected thyroid gland activated the
interferon pathways aligning with our results in the upregulation. (Poma et al. 2021)
Using your networks and results from the previous section add one of
the following: 1. Add a post analysis to your main network using
specific transcription factors, microRNAs or drugs. Include the reason
why you chose the specific miRs, TFs or drugs (i.e publications
indicating that they might be related to your model). What does this
post analysis show? 2, Choose a specific pathway or theme to investigate
in more detail. Why did you choose this pathway or theme? Show the
pathway or theme as a gene network or as a pathway diagram. Annotate the
network or pathway with your original log fold expression values and
p-values to show how it is effected in your model. (Hint: if the theme
or pathway is not from database that has detailed mechanistic
information like Reactome you can use apps like GeneMANIA or String to
build the the interaction network.) 3. Sometimes the most interesting
information is the gene that has no information. In this type of pathway
analysis we can only discover what we have already described previously
in the literature or pathway databases. Often pathways found in one
disease are applicable to other diseases so this technique can be very
helpful. It is important to highlight any genes that are significantly
differentially expressed in your model but are not annotated to any
pathways. We refer to this set of genes as the dark matter. Include a
heatmap of any significant genes that are not annotated to any of the
pathways returned in the enrichment analysis. Include a heatmap of any
significant genes that are not annotated to any pathways in entire set
of pathways used for the analysis.
#References
Durinck, Steffen, Paul T. Spellman, Ewan Birney, and Wolfgang Huber.
2009. “Mapping Identifiers for the Integration of Genomic Datasets
with the r/Bioconductor Package biomaRt.” Nature
Protocols 4: 1184–91.
Gu, Zuguang, Roland Eils, and Matthias Schlesner. 2016.
“Complex
Heatmaps Reveal Patterns and Correlations in Multidimensional Genomic
Data.” Bioinformatics.
https://doi.org/10.1093/bioinformatics/btw313.
Gu, Zuguang, Lei Gu, Roland Eils, Matthias Schlesner, and Benedikt
Brors. 2014. “Circlize Implements and Enhances Circular
Visualization in r.” Bioinformatics 30: 2811–12.
Lieberman, Nicole AP, Vikas Peddu, Hong Xie, Lasata Shrestha, Meei-Li
Huang, Megan C Mears, Maria N Cajimat, et al. 2020. “In Vivo
Antiviral Host Transcriptional Response to SARS-CoV-2 by Viral Load,
Sex, and Age.” PLoS Biology 18 (9): e3000849.
Morgan, Martin. 2022.
BiocManager: Access the Bioconductor Project
Package Repository.
https://CRAN.R-project.org/package=BiocManager.
Poma, Anna Maria, Alessandro Basolo, Daniele Bonuccelli, Agnese
Proietti, Elena Macerola, Clara Ugolini, Ludovica Torregrossa, et al.
2021.
“Activation of Type i and Type II Interferon Signaling in
SARS-CoV-2-Positive Thyroid Tissue of Patients Dying from
COVID-19.” Thyroid : Official Journal of the American Thyroid
Association 31 (12): 1766–75.
https://doi.org/10.1089/thy.2021.0345.
Raudvere, Uku, Liis Kolberg, Ivan Kuzmin, Tambet Arak, Priit Adler, Hedi
Peterson, and Jaak Vilo. 2019.
“G:profiler: A Web Server for
Functional Enrichment Analysis and Conversions of Gene Lists.”
Nucleic Acids Research.
https://doi.org/10.1093/nar/gkz369.
Robinson, Mark D, Davis J McCarthy, and Gordon K Smyth. 2010.
“edgeR: A Bioconductor Package for Differential Expression
Analysis of Digital Gene Expression Data.”
Bioinformatics 26 (1): 139–40.
https://doi.org/10.1093/bioinformatics/btp616.
Slowikowski, Kamil. 2023.
Ggrepel: Automatically Position
Non-Overlapping Text Labels with ’Ggplot2’.
https://CRAN.R-project.org/package=ggrepel.
Wickham, Hadley. 2016.
Ggplot2: Elegant Graphics for Data
Analysis. Springer-Verlag New York.
https://ggplot2.tidyverse.org.
Xie, Yihui. 2023.
Knitr: A General-Purpose Package for Dynamic
Report Generation in r.
https://yihui.org/knitr/.
Zhu, Yuelin, Sean Davis, Robert Stephens, Paul S. Meltzer, and Yidong
Chen. 2008.
“GEOmetadb: Powerful Alternative Search Engine for the
Gene Expression Omnibus.” Bioinformatics (Oxford,
England) 24 (23): 2798–2800.
https://doi.org/10.1093/bioinformatics/btn520.
LS0tDQp0aXRsZTogIkEzIg0KYXV0aG9yOiBKYWUgSHl1bmcgSnVuZw0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiAnMicNCiAgICBkZl9wcmludDogcGFnZWQNCiAgaHRtbF9ub3RlYm9vazoNCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogMg0KYmlibGlvZ3JhcGh5OiAnQTIuYmliJw0KLS0tDQoNCg0KW0BnZW9tZXRhZGJdDQpbQGtuaXRyXQ0KW0BlZGdlcl0NCltAYmlvY21hbmFnZXJdDQpbQGJpb21hcnRdDQpbQGNpcmNsaXplXQ0KW0Bjb21wbGV4XQ0KW0BnZ3Bsb3QyXQ0KW0BnZ3JlcGVsXQ0KW0BncHJvZmlsZV0NCmBgYHtyLCBtZXNzYWdlPSBGQUxTRX0NCmlmICghcmVxdWlyZU5hbWVzcGFjZSgiR0VPbWV0YWRiIiwgcXVpZXRseSA9IFRSVUUpKQ0KICBCaW9jTWFuYWdlcjo6aW5zdGFsbCgiR0VPbWV0YWRiIikNCg0KaWYgKCFyZXF1aXJlTmFtZXNwYWNlKCJrbml0ciIsIHF1aWV0bHkgPSBUUlVFKSkNCiAgaW5zdGFsbC5wYWNrYWdlcygia25pdHIiKQ0KDQppZiAoIXJlcXVpcmUoImVkZ2VSIiwgcXVpZXRseSA9IFRSVUUpKQ0KICBCaW9jTWFuYWdlcjo6aW5zdGFsbCgiZWRnZVIiKQ0KDQppZiAoIXJlcXVpcmVOYW1lc3BhY2UoIkJpb2NNYW5hZ2VyIiwgcXVpZXRseSA9IFRSVUUpKQ0KICBpbnN0YWxsLnBhY2thZ2VzKCJCaW9jTWFuYWdlciIpDQoNCmlmICghcmVxdWlyZU5hbWVzcGFjZSgiYmlvbWFSdCIsIHF1aWV0bHkgPSBUUlVFKSkNCiAgQmlvY01hbmFnZXI6Omluc3RhbGwoImJpb21hUnQiKQ0KDQppZiAoIXJlcXVpcmVOYW1lc3BhY2UoIkNvbXBsZXhIZWF0bWFwIiwgcXVpZXRseSA9IFRSVUUpKQ0KICBCaW9jTWFuYWdlcjo6aW5zdGFsbCgiQ29tcGxleEhlYXRtYXAiKQ0KDQppZiAoIXJlcXVpcmVOYW1lc3BhY2UoImNpcmNsaXplIiwgcXVpZXRseSA9IFRSVUUpKQ0KICBCaW9jTWFuYWdlcjo6aW5zdGFsbCgiY2lyY2xpemUiKQ0KDQppZiAoIXJlcXVpcmVOYW1lc3BhY2UoImdncGxvdDIiLCBxdWlldGx5ID0gVFJVRSkpDQogIGluc3RhbGwucGFja2FnZXMoImdncGxvdDIiKQ0KDQppZiAoIXJlcXVpcmVOYW1lc3BhY2UoImdncmVwZWwiLCBxdWlldGx5ID0gVFJVRSkpDQogIGluc3RhbGwucGFja2FnZXMoImdncmVwZWwiKQ0KDQpgYGANCg0KIyMgQ2FsbGluZyByZXF1aXJlZCBwYWNrYWdlcw0KDQpgYGB7ciwgbWVzc2FnZT1GQUxTRX0NCmxpYnJhcnkoQmlvY01hbmFnZXIpDQpsaWJyYXJ5KEdFT21ldGFkYikNCmxpYnJhcnkoa25pdHIpDQpsaWJyYXJ5KGVkZ2VSKQ0KbGlicmFyeShiaW9tYVJ0KQ0KbGlicmFyeShDb21wbGV4SGVhdG1hcCkNCmxpYnJhcnkoY2lyY2xpemUpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KGdncmVwZWwpDQpgYGANCg0KIyMgRG93bmxvYWQgdGhlIGRhdGENCiMjIyBHU0UxNTIwNzQgcmF3IGRhdGEgc3VwcGxlbW50YXJ5IGZpbGUgZG93bmxvYWRlZA0KDQpgYGB7ciwgbWVzc2FnZT1GQUxTRX0NCnNmaWxlcyA9IGdldEdFT1N1cHBGaWxlcygnR1NFMTUyMDc1JykNCmZuYW1lcyA9IHJvd25hbWVzKHNmaWxlcykNCiMgdGhlcmUgaXMgb25seSBvbmUgc3VwcGxlbWVudGFsIGZpbGUNCnJlYWREYXRhID0gcmVhZC50YWJsZShmbmFtZXNbMV0saGVhZGVyPVRSVUUsIGNoZWNrLm5hbWVzID0gVFJVRSkNCmBgYA0KIyMgRGF0YQ0KDQogRGF0YSBmcm9tIFtAbGllYmVybWFuMjAyMHZpdm9dLg0KYGBge3J9DQprYWJsZShyZWFkRGF0YVsxOjUsIDE6NV0sIHR5cGUgPSAiaHRtbCIsIHJvdy5uYW1lcyA9IFRSVUUpDQpgYGANCg0KIFRhYmxlIDE6IE9yaWdpbmFsIGRhdGEgY29udGFpbnMgSEdOQyBhbm5vdGF0aW9uIGFzIHJvdyBuYW1lcy4gQ29sdW1uIG5hbWVzIGhhdmUgcHJlZml4ZXMgYmVmb3JlIHRoZWlyIGlkZW50aWZpZXIgbnVtYmVyIGFzIGVpdGhlciBQT1Mgb3IgTkVHLiBDb3JyZXNwb25kaW5nIHRvIGVpdGhlciBwb3NpdGl2ZSBmb3IgQ09WSUQxOSBvciBuZWdhdGl2ZS4NCg0KDQoNCiMjIEFzc2Vzcw0KDQpBZGQgMSB0byBhbGwgdmFsdWVzIG9mIGRhdGEgc28gbGF0ZXIgb24gd2hlbiBjb25kdWN0aW5nIGxvZzIoY3BtKSB3ZSBjYW4gYXZvaWQgbmVnYXRpdmUgaW5maW5pdHkgdmFsdWVzLiAoQWR2aXNlZCBieSBQcm9mZXNzb3IgSXNzZXJsaW4pDQpgYGB7ciwgbWVzc2FnZT1GQUxTRX0NCnJlYWREYXRhIDwtIHJlYWREYXRhICsgMQ0KYGBgDQoNCg0KU2V0dGluZyBmaXJzdCBjb2x1bW4gYXMgZ2VuZSBpZCBmb3IgZnV0dXJlIGZvcm1hdCBwdXJwb3Nlcw0KYGBge3J9DQojUGxhY2Ugcm93bmFtZXMgaW4gZmlyc3QgY29sdW1uIGZvciBmdXR1cmUgZm9ybWF0IHB1cnBvc2VzDQppbnRlciA8LSBkYXRhLmZyYW1lKCJIVUdPIiA9IHJvd25hbWVzKHJlYWREYXRhKSkNCmdlbmVEYXRhIDwtIGNiaW5kKGludGVyJEhVR08sIHJlYWREYXRhKQ0KY29sbmFtZXMoZ2VuZURhdGEpWzFdIDwtICJIVUdPIg0KYGBgDQoNCiMjIENsZWFuDQpSZW1vdmUgYW55IG91dGxpZXJzIHRoYXQgZG9lcyBub3QgaGF2ZSBhdCBsZWFzdCAyIHJlYWQgcGVyIG1pbGxpb24gaW4gbiBvZiB0aGUgc2FtcGxlcy4NCldlIHNldCB0aGlzIGFzIDIgc2luY2Ugd2UgYWRkIDEgdG8gYWxsIG9mIG91ciBkYXRhc2V0IGluIHRoZSBiZWdpbm5pbmcgb2YgdGhlIGNvZGUgdG8gaGF2ZSBiZXR0ZXIgcGxvdHMuDQpEZW5vdGluZyBuIGFzIHRoZSBzbWFsbGVzdCBncm91cCBvZiByZXBsaWNhdGVzIHdoaWNoIGlzIHRoZSBjb250cm9sIGdyb3VwIG9mIDUzLg0KVXNpbmcgbiA9IDUzIGNvbmR1Y3QgdGhlIHJlbW92YWwgb2YgbG93IGNvdW50cy4NCmBgYHtyfQ0KI3RyYW5zbGF0ZSBvdXQgY291bnRzIGludG8gY291bnRzIHBlciBtaWxsaXNvbiB1c2luZyANCiN0aGUgZWRnZVIgcGFja2FnZSBmdW5jdGlvbiBjcG0NCmNwbXMgPSBjcG0oZ2VuZURhdGFbLDI6NDg1XSkNCnJvd25hbWVzKGNwbXMpIDwtIGdlbmVEYXRhWywxXQ0KIyBnZXQgcmlkIG9mIGxvdyBjb3VudHMNCmtlZXAgPSByb3dTdW1zKGNwbXMgPjIpID49NTMNCmdlbmVEYXRhX2V4cF9maWx0ZXJlZCA9IGdlbmVEYXRhW2tlZXAsXQ0KYGBgDQoNClJlbW92ZSB2ZXJzaW9uIG51bWJlcnMgaWYgdGhleSBleGlzdHMgb24gZ2VuZSBpZChIVUdPKSBjb2x1bW4uDQpUaGlzIG1ha2VzIGl0IGVhc2llciBmb3IgbWFwcGluZyBsYXRlciBvbi4NCmBgYHtyfQ0KZ2VuZURhdGFfZXhwX2ZpbHRlcmVkWywxXSA8LSBnc3ViKCJcXC5bMC05XSIsICIiLCBnZW5lRGF0YV9leHBfZmlsdGVyZWRbLDFdKQ0KYGBgDQoNCiMjIE1hcA0KYGBge3IsIG1lc3NhZ2U9RkFMU0V9DQojTWFwcGluZyB0aGUgbmFtZSB1c2luZyBiaW9tYXRyDQojIGxpc3QgYXZhaWxhYmxlIGdlbmUgYW5ub3RhdGlvbiBkYXRhYmFzZXMNCmJpbyA8LSB1c2VNYXJ0KCJlbnNlbWJsIiwgZGF0YXNldCA9ICJoc2FwaWVuc19nZW5lX2Vuc2VtYmwiKQ0KY29udmVyc2lvbl9zdGFzaCA8LSAiZ2VuZU1hcHBpbmcucmRzIg0KaWYoZmlsZS5leGlzdHMoY29udmVyc2lvbl9zdGFzaCkpew0KICBnZW5lTWFwcGluZyA8LSByZWFkUkRTKGNvbnZlcnNpb25fc3Rhc2gpDQp9IGVsc2V7DQojIGNvbnZlcnQgY29sdW1uIG9mIGdlbmUgSURzIHRvIEh1Z28gc3ltYm9scw0KZ2VuZU1hcHBpbmcgPC0gZ2V0Qk0oYXR0cmlidXRlcyA9IGMoImVuc2VtYmxfZ2VuZV9pZCIsICJoZ25jX3N5bWJvbCIpLA0KICAgICAgICAgICAgICAgICAgICAgbWFydCA9IGJpbywNCiAgICAgICAgICAgICAgICAgICAgIGZpbHRlcnMgPSAiaGduY19zeW1ib2wiLA0KICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gZ2VuZURhdGFfZXhwX2ZpbHRlcmVkWywxXSkNCnNhdmVSRFMoZ2VuZU1hcHBpbmcsIGNvbnZlcnNpb25fc3Rhc2gpDQp9DQpgYGANCg0KQ29tYmluZSB0aGUgbWFwcGVkIGdlbmUgZGF0YSB0byBvcmlnaW5hbCBkYXRhDQpgYGB7cn0NCiNNZXJnZSB0aGUgZGF0YQ0KbWVyZ2VkRGF0YSA8LSBtZXJnZShnZW5lRGF0YV9leHBfZmlsdGVyZWQsIGdlbmVNYXBwaW5nLCBieS54ID0gMSwgYnkueSA9IDIpDQojcmVtb3ZlIGR1cGxpY2F0ZSByb3dzIGluIHRoZSBnZW5lIGRhdGENCm1lcmdlZERhdGFOb0R1cCA8LSBtZXJnZWREYXRhWyFkdXBsaWNhdGVkKG1lcmdlZERhdGFbLDE6NDg1XSksXQ0KDQpgYGANCg0KIyMgQXBwbHkgTm9ybWFsaXphdGlvbg0KUmFuZG9tbHkgc2FtcGxlIGRhdGEgdG8gcmVkdWNlIHRoZSBzaXplIG9mIHNhbXBsZS4gT3JpZ2luYWwgc2FtcGxlIGlzIHRvbyBsYXJnZQ0KbGVhZGluZyB0byBjb21wdXRhdGlvbiBlcnJvcnMgZHVlIHRvIHRoZSBsaW1pdGF0aW9uIG9mIGF1dGhvcidzIGNvbXB1dGVyLg0KYGBge3J9DQoNCnNldC5zZWVkKDEyMzQ1KQ0KcmFuZG9tU2FtcGxlUE9TIDwtIHNhbXBsZShtZXJnZWREYXRhTm9EdXBbMjo0MzFdLCAyNSkNCnJhbmRvbVNhbXBsZU5FRyA8LSBzYW1wbGUobWVyZ2VkRGF0YU5vRHVwWzQzMjo0ODVdLCAyNSkNCnJhbmRvbVNhbXBsZSA8LSBjYmluZChyYW5kb21TYW1wbGVQT1MscmFuZG9tU2FtcGxlTkVHLCBtZXJnZWREYXRhTm9EdXAkZW5zZW1ibF9nZW5lX2lkLCBtZXJnZWREYXRhTm9EdXAkSFVHTykNCg0KDQpgYGANCg0KRGVmaW5lIGdyb3VwcyB0byB1c2UgaW4gbm9ybWFsaXphdGlvbg0KYGBge3J9DQoNCnNhbXBsZXMgPC0gZGF0YS5mcmFtZShsYXBwbHkoY29sbmFtZXMocmFuZG9tU2FtcGxlWzE6NTBdKSwgDQogICAgICAgIEZVTj1mdW5jdGlvbih4KXt1bmxpc3Qoc3Ryc3BsaXQoeCwgDQogICAgICAgICAgICAgICAgICAgICAgICBzcGxpdCA9ICJfIikpW2MoMiwxKV19KSkNCmNvbG5hbWVzKHNhbXBsZXMpIDwtIGNvbG5hbWVzKHJhbmRvbVNhbXBsZVsxOjUwXSkNCnJvd25hbWVzKHNhbXBsZXMpIDwtIGMoInBhdGllbnRzIiwiY2VsbF90eXBlIikNCnNhbXBsZXMgPC0gZGF0YS5mcmFtZSh0KHNhbXBsZXMpKQ0KDQpgYGANCg0KDQpBcHBseWluZyBUTU0gdG8gZGF0YQ0KYGBge3J9DQoNCmZpbHRlcmVkX2RhdGFfbWF0cml4IDwtIGFzLm1hdHJpeChyYW5kb21TYW1wbGVbMTo1MF0pDQpyb3duYW1lcyhmaWx0ZXJlZF9kYXRhX21hdHJpeCkgPC0gcmFuZG9tU2FtcGxlJGBtZXJnZWREYXRhTm9EdXAkZW5zZW1ibF9nZW5lX2lkYA0KZCA9IERHRUxpc3QoY291bnRzPWZpbHRlcmVkX2RhdGFfbWF0cml4LCBncm91cD1zYW1wbGVzJGNlbGxfdHlwZSkNCg0KZCA9IGNhbGNOb3JtRmFjdG9ycyhkKQ0KDQpub3JtYWxpemVkX2NvdW50cyA8LSBjcG0oZCkNCiNhZGQgY29sdW1ucyBvZiBlbnNlbWJsIGFuZCBoZ25jIGlkDQoNCm5vcm1hbGl6ZWRfY291bnRfZGF0YSA9IGRhdGEuZnJhbWUobm9ybWFsaXplZF9jb3VudHMpDQpub3JtYWxpemVkX2NvdW50X2RhdGEkZW5zZW1ibF9nZW5lX2lkIDwtIG1lcmdlZERhdGFOb0R1cCRlbnNlbWJsX2dlbmVfaWQNCm5vcm1hbGl6ZWRfY291bnRfZGF0YSRoZ25jX3N5bWJvbCA8LSBtZXJnZWREYXRhTm9EdXAkSFVHTw0KDQoNCiNUaGlzIGlzIGEgZHVwbGljYXRlIGVuc2VtYmwgaWQgdGhhdCBpcyBnaXZpbmcgZXJyb3JzIHdoZW4gcnVubmluZyBjb2RlLg0Kbm9ybWFsaXplZF9jb3VudF9kYXRhIDwtIG5vcm1hbGl6ZWRfY291bnRfZGF0YVstYygxOTAyKSxdDQpgYGANCg0KDQpgYGB7cn0NCm1vZGVsX2Rlc2lnbiA8LSBtb2RlbC5tYXRyaXgofnNhbXBsZXMkY2VsbF90eXBlKzApDQpkIDwtIGVzdGltYXRlRGlzcChkLCBtb2RlbF9kZXNpZ24pDQpgYGANCg0KIyBEaWZmZXJlbnRpYWwgR2VuZSBFeHByZXNzaW9uDQoNCiMjIExJTU1BDQpwLXZhbHVlIGNhbGN1bGF0aW9uIHVzaW5nIExJTU1BDQpgYGB7cn0NCm1vZGVsX2Rlc2lnbiA8LSBtb2RlbC5tYXRyaXgofiBzYW1wbGVzJGNlbGxfdHlwZSApDQpgYGANCg0KYGBge3J9DQoNCmV4cHJlc3Npb25NYXRyaXggPC0gYXMubWF0cml4KG5vcm1hbGl6ZWRfY291bnRfZGF0YVssMTo1MF0pDQpyb3duYW1lcyhleHByZXNzaW9uTWF0cml4KSA8LSANCiAgbm9ybWFsaXplZF9jb3VudF9kYXRhJGVuc2VtYmxfZ2VuZV9pZA0KY29sbmFtZXMoZXhwcmVzc2lvbk1hdHJpeCkgPC0gDQogIGNvbG5hbWVzKG5vcm1hbGl6ZWRfY291bnRfZGF0YSlbMTo1MF0NCm1pbmltYWxTZXQgPC0gRXhwcmVzc2lvblNldChhc3NheURhdGE9ZXhwcmVzc2lvbk1hdHJpeCkNCg0KYGBgDQoNCg0KVGFraW5nIGludG8gYWNjb3VudCBQYXRpZW50IHZhcmlhYmlsaXR5DQpgYGB7cn0NCm1vZGVsX2Rlc2lnbl9wYXQgPC0gbW9kZWwubWF0cml4KA0KICB+IHNhbXBsZXMkcGF0aWVudHMgKyBzYW1wbGVzJGNlbGxfdHlwZSkNCmBgYA0KDQpgYGB7cn0NCmZpdF9wYXQgPC0gbG1GaXQobWluaW1hbFNldCwgbW9kZWxfZGVzaWduX3BhdCkNCmBgYA0KDQoNCmBgYHtyfQ0KZml0Ml9wYXQgPC0gZUJheWVzKGZpdF9wYXQsdHJlbmQ9VFJVRSkNCg0KdG9wZml0X3BhdCA8LSB0b3BUYWJsZShmaXQyX3BhdCwgDQogICAgICAgICAgICAgICAgICAgY29lZj1uY29sKG1vZGVsX2Rlc2lnbl9wYXQpLA0KICAgICAgICAgICAgICAgICAgIGFkanVzdC5tZXRob2QgPSAiQkgiLA0KICAgICAgICAgICAgICAgICAgIG51bWJlciA9IG5yb3coZXhwcmVzc2lvbk1hdHJpeCkpDQojbWVyZ2UgaGduYyBuYW1lcyB0byB0b3BmaXQgdGFibGUNCm91dHB1dF9oaXRzX3BhdCA8LSBtZXJnZShub3JtYWxpemVkX2NvdW50X2RhdGFbLDUxOjUyXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICB0b3BmaXRfcGF0LGJ5Lnk9MCxieS54PTEsYWxsLnk9VFJVRSkNCiNzb3J0IGJ5IHB2YWx1ZQ0Kb3V0cHV0X2hpdHNfcGF0IDwtIG91dHB1dF9oaXRzX3BhdFtvcmRlcihvdXRwdXRfaGl0c19wYXQkUC5WYWx1ZSksXQ0KYGBgDQoNCmBgYHtyfQ0KbGVuZ3RoKHdoaWNoKG91dHB1dF9oaXRzX3BhdCRQLlZhbHVlIDwgMC4wNSkpDQpsZW5ndGgod2hpY2gob3V0cHV0X2hpdHNfcGF0JGFkai5QLlZhbCA8IDAuMDUpKQ0KYGBgDQoNCiMjIFFMRg0KDQpgYGB7cn0NCmQgPSBER0VMaXN0KGNvdW50cz1maWx0ZXJlZF9kYXRhX21hdHJpeCwgZ3JvdXA9c2FtcGxlcyRjZWxsX3R5cGUpDQpgYGANCmBgYHtyfQ0KZCA8LSBlc3RpbWF0ZURpc3AoZCwgbW9kZWxfZGVzaWduX3BhdCkNCmBgYA0KDQpgYGB7cn0NCmZpdCA8LSBnbG1RTEZpdChkLCBtb2RlbF9kZXNpZ25fcGF0KQ0KYGBgDQoNCg0KYGBge3J9DQpxbGYucG9zX3ZzX25lZyA8LSBnbG1RTEZUZXN0KGZpdCwgY29lZj0nc2FtcGxlcyRjZWxsX3R5cGVQT1MnKQ0Ka2FibGUodG9wVGFncyhxbGYucG9zX3ZzX25lZyksIHR5cGU9Imh0bWwiLHJvdy5uYW1lcyA9IEZBTFNFKQ0KYGBgDQoNClAtdmFsdWVzIHdlcmUgY29ycmVjdGVkIHVzaW5nIFF1YXNpbGlrZWxpaG9vZCBtZXRob2QuDQpRdWFzaWxpa2VsaWhvb2QgaXMgYmV0dGVyIGJlY2FjdXNlIGl0IGlzIHRhaWxvcmVkIHRvd2FyZHMgUk5Bc2VxIGRhdGENCg0KYGBge3J9DQpxbGZfb3V0cHV0X2hpdHMgPC0gdG9wVGFncyhxbGYucG9zX3ZzX25lZyxzb3J0LmJ5ID0gIlBWYWx1ZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICBuID0gbnJvdyhub3JtYWxpemVkX2NvdW50X2RhdGEpKQ0KbGVuZ3RoKHdoaWNoKHFsZl9vdXRwdXRfaGl0cyR0YWJsZSRQVmFsdWUgPCAwLjA1KSkNCmxlbmd0aCh3aGljaChxbGZfb3V0cHV0X2hpdHMkdGFibGUkRkRSIDwgMC4wNSkpDQpgYGANCg0KIyBUaHJlc2hvbGRlZCBvdmVyLXJlcHJlc2VudGF0aW9uIGFuYWx5c2lzDQoNCiMjIFdyaXRlIHRvIGZpbGUgdXByZWd1bGF0ZWQsIGFuZCBkb3ducmVndWxhdGVkIGdlbmVzDQoNCldoaWNoIG9uZXMgYXJlIHVwcmVndWxhdGVkIGFuZCBkb3ducmVndWxhdGVkDQpgYGB7cn0NCmxlbmd0aCh3aGljaChxbGZfb3V0cHV0X2hpdHMkdGFibGUkUFZhbHVlIDwgMC4wNSANCiAgICAgICAgICAgICAmIHFsZl9vdXRwdXRfaGl0cyR0YWJsZSRsb2dGQyA+IDApKQ0KDQpsZW5ndGgod2hpY2gocWxmX291dHB1dF9oaXRzJHRhYmxlJFBWYWx1ZSA8IDAuMDUgDQogICAgICAgICAgICAgJiBxbGZfb3V0cHV0X2hpdHMkdGFibGUkbG9nRkMgPCAwKSkNCmBgYA0KDQpgYGB7cn0NCnFsZl9vdXRwdXRfaGl0c193aXRoZ24gPC0gbWVyZ2UocmFuZG9tU2FtcGxlWyw1MTo1Ml0scWxmX291dHB1dF9oaXRzLCBieS54PTEsIGJ5LnkgPSAwKQ0KI251bWJlciBoaWdoZXIgdGhlIGxvd2VyIHRoZSBwdmFsdWUsIGFuZCBpZiBpdCBpcyB1cHJlZ3VsYXRlZCBudW1iZXIgaXMgcG9zaXRpdmUsIGFuZCBuZWdhdGl2ZSBmb3IgZG93bnJlZ3VsYXRlZA0KcWxmX291dHB1dF9oaXRzX3dpdGhnblssInJhbmsiXSA8LSAtbG9nKHFsZl9vdXRwdXRfaGl0c193aXRoZ24kUFZhbHVlLGJhc2UgPTEwKSAqIHNpZ24ocWxmX291dHB1dF9oaXRzX3dpdGhnbiRsb2dGQykNCnFsZl9vdXRwdXRfaGl0c193aXRoZ24gPC0gcWxmX291dHB1dF9oaXRzX3dpdGhnbltvcmRlcihxbGZfb3V0cHV0X2hpdHNfd2l0aGduJHJhbmspLF0NCnVwcmVndWxhdGVkX2dlbmVzIDwtIHFsZl9vdXRwdXRfaGl0c193aXRoZ24kYG1lcmdlZERhdGFOb0R1cCRIVUdPYFsNCiAgd2hpY2gocWxmX291dHB1dF9oaXRzX3dpdGhnbiRQVmFsdWUgPCAwLjA1IA0KICAgICAgICAgICAgICYgcWxmX291dHB1dF9oaXRzX3dpdGhnbiRsb2dGQyA+IDApXQ0KZG93bnJlZ3VsYXRlZF9nZW5lcyA8LSBxbGZfb3V0cHV0X2hpdHNfd2l0aGduJGBtZXJnZWREYXRhTm9EdXAkSFVHT2BbDQogIHdoaWNoKHFsZl9vdXRwdXRfaGl0c193aXRoZ24kUFZhbHVlIDwgMC4wNSANCiAgICAgICAgICAgICAmIHFsZl9vdXRwdXRfaGl0c193aXRoZ24kbG9nRkMgPCAwKV0NCndyaXRlLnRhYmxlKHg9dXByZWd1bGF0ZWRfZ2VuZXMsDQogICAgICAgICAgICBmaWxlPWZpbGUucGF0aCgiZGF0YSIsInVwcmVndWxhdGVkX2dlbmVzLnR4dCIpLHNlcCA9ICJcdCIsDQogICAgICAgICAgICByb3cubmFtZXMgPSBGQUxTRSxjb2wubmFtZXMgPSBGQUxTRSxxdW90ZSA9IEZBTFNFKQ0Kd3JpdGUudGFibGUoeD1kb3ducmVndWxhdGVkX2dlbmVzLA0KICAgICAgICAgICAgZmlsZT1maWxlLnBhdGgoImRhdGEiLCJkb3ducmVndWxhdGVkX2dlbmVzLnR4dCIpLHNlcCA9ICJcdCIsDQogICAgICAgICAgICByb3cubmFtZXMgPSBGQUxTRSxjb2wubmFtZXMgPSBGQUxTRSxxdW90ZSA9IEZBTFNFKQ0Kd3JpdGUudGFibGUoeD1kYXRhLmZyYW1lKGdlbmVuYW1lPSBxbGZfb3V0cHV0X2hpdHNfd2l0aGduJGBtZXJnZWREYXRhTm9EdXAkSFVHT2AsRl9zdGF0PSBxbGZfb3V0cHV0X2hpdHNfd2l0aGduJHJhbmspLA0KICAgICAgICAgICAgZmlsZT1maWxlLnBhdGgoImRhdGEiLCJyYW5rZWRfZ2VuZWxpc3QudHh0Iiksc2VwID0gIlx0IiwNCiAgICAgICAgICAgIHJvdy5uYW1lcyA9IEZBTFNFLGNvbC5uYW1lcyA9IEZBTFNFLHF1b3RlID0gRkFMU0UpDQpgYGANCg0KIyBOb24tdGhyZXNob2xkZWQgR2VuZSBzZXQgRW5yaWNobWVudCBBbmFseXNpcw0KDQpgYGB7cn0NCmdtdF91cmwgPSAiaHR0cDovL2Rvd25sb2FkLmJhZGVybGFiLm9yZy9FTV9HZW5lc2V0cy9jdXJyZW50X3JlbGVhc2UvSHVtYW4vc3ltYm9sLyINCiMgbGlzdCBhbGwgdGhlIGZpbGVzIG9uIHRoZSBzZXJ2ZXINCmZpbGVuYW1lcyA9IFJDdXJsOjpnZXRVUkwoZ210X3VybCkNCnRjID0gdGV4dENvbm5lY3Rpb24oZmlsZW5hbWVzKQ0KY29udGVudHMgPSByZWFkTGluZXModGMpDQpjbG9zZSh0YykNCiMgZ2V0IHRoZSBnbXQgdGhhdCBoYXMgYWxsIHRoZSBwYXRod2F5cyBhbmQgZG9lcyBub3QgaW5jbHVkZSB0ZXJtcyBpbmZlcnJlZA0KIyBmcm9tIGVsZWN0cm9uaWMgYW5ub3RhdGlvbnMoSUVBKSBzdGFydCB3aXRoIGdtdCBmaWxlIHRoYXQgaGFzIHBhdGh3YXlzIG9ubHkNCnJ4ID0gZ3JlZ2V4cHIoIig/PD08YSBocmVmPVwiKSguKi5HT0JQX0FsbFBhdGh3YXlzX25vX0dPX2llYS4qLikoLmdtdCkoPz1cIj4pIiwgY29udGVudHMsDQogICAgcGVybCA9IFRSVUUpDQpnbXRfZmlsZSA9IHVubGlzdChyZWdtYXRjaGVzKGNvbnRlbnRzLCByeCkpDQpkZXN0X2dtdF9maWxlIDwtIGZpbGUucGF0aChkYXRhX2RpciwgZ210X2ZpbGUpDQpkb3dubG9hZC5maWxlKHBhc3RlKGdtdF91cmwsIGdtdF9maWxlLCBzZXAgPSAiIiksICJiYWRlcl9sYWIuZ210IikNCmBgYA0KDQpDb25kdWN0IG5vbi10aHJlc2hvbGRlZCBnZW5lIHNldCBlbnJpY2htZW50IGFuYWx5c2lzIHVzaW5nIHRoZSByYW5rZWQgc2V0IG9mIGdlbmVzIGZyb20gQXNzaWdubWVudCAjMi4NCg0KMS4gV2hhdCBtZXRob2QgZGlkIHlvdSB1c2U/IFdoYXQgZ2VuZXNldHMgZGlkIHlvdSB1c2U/IE1ha2Ugc3VyZSB0byBzcGVjaWZ5IHZlcnNpb25zIGFuZCBjaXRlIHlvdXIgbWV0aG9kcy4NCkkgdXNlZCB0aGUgR1NFQSBkZXNrdG9wIGFwcGxpY2F0aW9uIHRvIHJ1biBHU0VBICBTdWJyYW1hbmlhbiwgVGFtYXlvLCBldCBhbC4gKDIwMDUsIFBOQVMpIGFuZCBNb290aGEsIExpbmRncmVuLCBldCBhbC4gKDIwMDMsIE5hdHVyZSBHZW5ldGljcykuIA0KSSB1c2VkIHRoZSBnZW5lc2V0cyBmcm9tIHRoZSBiYWRlciBsYWIgZXh0cmFjdGVkIGZyb20gdGhlIGNvZGUgYWJvdmUgSSB1c2VkLiBPciBpdCBjYW4gYmUgcmV0cmlldmVkIGZyb20gaGVyZSBodHRwOi8vZG93bmxvYWQuYmFkZXJsYWIub3JnL0VNX0dlbmVzZXRzL2N1cnJlbnRfcmVsZWFzZS9IdW1hbi9zeW1ib2wvLg0KMi4gU3VtbWFyaXplIHlvdXIgZW5yaWNobWVudCByZXN1bHRzLg0KU0FScy1Db1YtMiBwb3NpdGl2ZSBzYW1wbGVzOg0KNDk2NSAvIDYwNzQgZ2VuZSBzZXRzIGFyZSB1cHJlZ3VsYXRlZCBpbiBwaGVub3R5cGUgbmFfcG9zDQo0NDIgZ2VuZSBzZXRzIGFyZSBzaWduaWZpY2FudCBhdCBGRFIgPCAyNSUNCjQxMCBnZW5lIHNldHMgYXJlIHNpZ25pZmljYW50bHkgZW5yaWNoZWQgYXQgbm9taW5hbCBwdmFsdWUgPCAxJQ0KNjYyIGdlbmUgc2V0cyBhcmUgc2lnbmlmaWNhbnRseSBlbnJpY2hlZCBhdCBub21pbmFsIHB2YWx1ZSA8IDUlDQpUb3AgZ2VuZS1zZXQ6IEhBTExNQVJLX0lOVEVSRkVST05fQUxQSEFfUkVTUE9OU0UlTVNJR0RCSEFMTE1BUkslSEFMTE1BUktfSU5URVJGRVJPTl9BTFBIQV9SRVNQT05TRQ0KTnVtYmVyIG9mIGdlbmVzIGluIGxlYWRpbmcgZWRnZTogODANClRvcCBnZW5lIGFzc29jaWF0ZWQ6IENYQ0wxMQ0KDQpTQVJzLUNvVi0yIG5lZ2F0aXZlIHNhbXBsZXM6DQoxMTA5IC8gNjA3NCBnZW5lIHNldHMgYXJlIHVwcmVndWxhdGVkIGluIHBoZW5vdHlwZSBuYV9uZWcNCjI3NCBnZW5lIHNldHMgYXJlIHNpZ25pZmljYW50bHkgZW5yaWNoZWQgYXQgRkRSIDwgMjUlDQoxOTYgZ2VuZSBzZXRzIGFyZSBzaWduaWZpY2FudGx5IGVucmljaGVkIGF0IG5vbWluYWwgcHZhbHVlIDwgMSUNCjI3NiBnZW5lIHNldHMgYXJlIHNpZ25pZmljYW50bHkgZW5yaWNoZWQgYXQgbm9taW5hbCBwdmFsdWUgPCA1JQ0KVG9wIGdlbmUtc2V0OiBFTkVSR1kgREVSSVZBVElPTiBCWSBPWElEQVRJT04gT0YgT1JHQU5JQyBDT01QT1VORFMlR09CUCVHTzowMDE1OTgwDQpOdW1iZXIgb2YgZ2VuZXMgaW4gbGVhZGluZyBlZGdlOiAxNjUNClRvcCBnZW5lIGFzc29jaWF0ZWQ6IFRFRk0NCjMuIEhvdyBkbyB0aGVzZSByZXN1bHRzIGNvbXBhcmUgdG8gdGhlIHJlc3VsdHMgZnJvbSB0aGUgdGhyZXNob2xkZWQgYW5hbHlzaXMgaW4gQXNzaWdubWVudCAjMi4gQ29tcGFyZSBxdWFsaXRhdGl2ZWx5LiBJcyB0aGlzIGEgc3RyYWlnaHQgZm9yd2FyZCBjb21wYXJpc29uPyBXaHkgb3Igd2h5IG5vdD8NCkZvciB0aGUgdXByZWd1bGF0ZWQgZ2VuZXMgdGhlIHRvcCByZXN1bHRzIGFyZSBuZWdhdGl2ZSByZWd1bGF0aW9uIG9mIHZpcmFsIGdlbm9tZSByZXBsaWNhdGlvbiwgbmVnYXRpdmUgcmVndWxhdGlvbiBvZiB2aXJhbCBwcm9jZXNzLCByZXNwb25zZSB0byB0eXBlIElJIGludGVyZmVyb24uIGRvd25yZWd1bGF0ZWQgd2UgZ290IGN5dG9wbGFzbWljIHRyYW5zbGF0aW9uLCBwb3NpdGl2ZSByZWd1bGF0aW9uIG9mIHJlc3BpcmF0b3J5IGJ1cnN0LCBhbmQgaW50ZXJtZWRpYXRlIGZpbGFtZW50LWJhc2VkIHByb2Nlc3MuIEkgaGFkIHRvbyBtYW55IGdlbmVzIHNvIEkgY291bGRuJ3QgcnVuIGFsbCB0aGUgZ2VuZXMgYXQgb25jZSBmb3IgbXkgd2hvbGUgbGlzdC4gRm9yIHVwcmVndWxhdGVkIGluIHRocmVzaG9sZGVkIGFuZCBub24tdGhyZXNob2xkZWQgdGhleSBhbGlnbiBhIGJpdCB0b2dldGhlciBieSBoYXZpbmcgaW50ZXJmZXJvbiByZWxhdGVkIHBhdGh3YXkgcmVzdWx0cy4gT3RoZXIgdGhlbiB0aGF0IHRoZXkgZG9uJ3Qgc2VlbSB0byBiZSBzaW1pbGFyLiBBIGNvbW1vbiBwYXRod2F5IGluIGRvd25yZWd1bGF0ZWQgYW5kIGFuZCBhbGwgb2YgdGhlIGdlbmVzIGZvciB0aHJlc2hvbGRlZCB3YXMgYSBwYXRod2F5IHJlbGF0ZWQgdG8gY3l0b3BsYXNtaWMuIEhvd2V2ZXIgaW4gbm9uIHRocmVzaG9sZGVkIHRoZXJlIHdlcmUgY3l0b3BsYXNtaWMgcmVsYXRlZCBwYXRod2F5cyBidXQgd2VyZSB2ZXJ5IGxvdyBpbiB0aGUgbGlzdC4gSXQgaXMgbm90IGEgc3RyYWlnaHQgZm9yd2FyZCBjb21wYXJpc29uIHRoZXkgYm90aCBoYXZlIGRpZmZlcmVudCB2YWx1ZXMgYXMgYW5hbHlzaXMuIFRoZSB0aHJlc2hvbGVkIGNvdWxkIGJlIG1vcmUgc2Vuc2l0aXZlIHdoaWxlIHRoZSBub24tdGhyZXNob2xkZWQgYmUgbW9yZSBnZW5lcmFsLg0KDQoNCg0KDQpVc2luZyB5b3VyIHJlc3VsdHMgZnJvbSB5b3VyIG5vbi10aHJlc2hvbGRlZCBnZW5lIHNldCBlbnJpY2htZW50IGFuYWx5c2lzIHZpc3VhbGl6ZSB5b3VyIHJlc3VsdHMgaW4gQ3l0b3NjYXBlLg0KDQpyZWQgLSB1cHJlZ3VsYXRlZCBmcm9tIG5lZyB0byBwb3MsIGJsdWUgLSBkb3ducmVndWxhdGVkIGluIHBvc2l0aXZlIGNvdmlkMTkgcGF0aWV0bnMgY29tcGFyZWQgdG8gbmVnYXRpdmUgcGF0aWVudHMuIA0KcmFua2VkIGxpc3QgPSBkZXBlbmRpbmcgb24gdGhlIGV4cHJlc3Npb24gb2YgYSBnZW5lIGluIHBvcyBjb21wYXJlZCB0byBuZWcNCg0KIyMgMS4gDQojIyMgQ3JlYXRlIGFuIGVucmljaG1lbnQgbWFwIC0gaG93IG1hbnkgbm9kZXMgYW5kIGhvdyBtYW55IGVkZ2VzIGluIHRoZSByZXN1bHRpbmcgbWFwPw0KMzc5IE5vZGVzDQoxNTExIEVkZ2VzDQoNCiMjIyBXaGF0IHRocmVzaG9sZHMgd2VyZSB1c2VkIHRvIGNyZWF0ZSB0aGlzIG1hcD8gDQpGRFIgcS12YWx1ZSBjdXRvZmY6IDAuMQ0KQW5hbHlzaXMgVHlwZTogR1NFQQ0KTm9kZSBjdXRvZmY6IDAuMSANCkVkZ2UgY3V0b2ZmOiAwLjM3NQ0KDQojIyMgTWFrZSBzdXJlIHRvIHJlY29yZCBhbGwgdGhyZXNob2xkcy4gSW5jbHVkZSBhIHNjcmVlbnNob3Qgb2YgeW91ciBuZXR3b3JrIHByaW9yIHRvIG1hbnVhbCBsYXlvdXQuDQogIVtGaWd1cmU6IFNjcmVlbnNob3Qgb2YgbmV0d29yayBwcmlvciB0byBtYW51YWwgbGF5b3V0XSguL2ZpZ3VyZS9wcmlvcnRvbWFudWFsLnBuZykNCg0KIyMjIDIuIEFubm90YXRlIHlvdXIgbmV0d29yayAtIHdoYXQgcGFyYW1ldGVycyBkaWQgeW91IHVzZSB0byBhbm5vdGF0ZSB0aGUgbmV0d29yay4gSWYgeW91IGFyZSB1c2luZyB0aGUgZGVmYXVsdCBwYXJhbWV0ZXJzIG1ha2Ugc3VyZSB0byBsaXN0IHRoZW0gYXMgd2VsbC4NClVzZWQgdGhlIGF1dG8gYW5ub3RhdGUgYXBwbGljYXRpb24gaW4gY3l0b3NjYXBlLiANCkNsdXN0ZXIgYWxnb3JpdGhtOiBNQ0wgQ2x1c3Rlcg0KTGFiZWwgQ29sdW1uOiBHU19ERVNDUg0KTGFiZWwgQWxnb3JpdGhtOiBXb3JkQ2xvdWQ6IEFkamFjZW50IFdvcmRzKGRlZmF1bHQpDQpNYXggd29yZHMgcGVyIGxhYmVsOiAzDQpNaW5pbXVtIHdvcmQgb2NjdXJyZW5jZTogMQ0KQWRqYWNlbnQgd29yZCBib251czogOA0KQm9yZGVyIFdpZHRoOiAzDQpPcGFjaXR5OiAyMCUNCkZvbnQgU2NhbGU6IDIwJQ0KDQoNCiAhW0ZpZ3VyZTogQW5ub3RhdGVkIG5ldHdvcmtdKC4vZmlndXJlL2Fubm90YXRlZG5ldHdvcmsucG5nKQ0KDQojIyMgMy4gTWFrZSBhIHB1YmxpY2F0aW9uIHJlYWR5IGZpZ3VyZSAtIGluY2x1ZGUgdGhpcyBmaWd1cmUgd2l0aCBwcm9wZXIgbGVnZW5kcyBpbiB5b3VyIG5vdGVib29rLg0KDQoNCiMjIyA0LiBDb2xsYXBzZSB5b3VyIG5ldHdvcmsgdG8gYSB0aGVtZSBuZXR3b3JrLiBXaGF0IGFyZSB0aGUgbWFqb3IgdGhlbWVzIHByZXNlbnQgaW4gdGhpcyBhbmFseXNpcz8gRG8gdGhleSBmaXQgd2l0aCB0aGUgbW9kZWw/IEFyZSB0aGVyZSBhbnkgbm92ZWwgcGF0aHdheXMgb3IgdGhlbWVzPw0KICFbRmlndXJlOiBDb2xsYXBzZWRdKC4vZmlndXJlL2NvbGxhcHNlZC5wbmcpDQpNYWpvciB0aGVtZXMgcHJlc2VudDoNClVwcmVndWxhdGVkOg0KLSBHUENSUyBSaG9kb3BzaW4gbGlnYW5kDQotIENoZW1va2luZSBNaWdyYXRpb24gY2hlbW90YXhpcw0KLSBDZWxsdWxhciByZXNwb25zZSBuZWNyb3Npcw0KLSB0eXBlIElJIGludGVyZmVyb24NCi0gTWlncmF0aW9uIG1vbm9jeXRlIGNoZW1vdGF4aXMNCi0gU3VyZmFjZSByZWNlcHRvciBwYXR0ZXJuDQoNCkRvd25yZWd1bGF0ZWQ6IA0KLSBnbHVjb25lb2dlbmVzaXMgZ2x5Y29seXNpcw0KLSBzdXBlcnBhdGh3YXkgd2FyYnVyZyBlZmZlY3QNCi0gc3JwIHByb3RlaW4gc3ludGhlc2lzIA0KDQpQcmVzZW50IHlvdXIgcmVzdWx0cyB3aXRoIHRoZSB1c2Ugb2YgdGFibGVzIGFuZCBzY3JlZW5zaG90cy4gQWxsIGZpZ3VyZXMgc2hvdWxkIGhhdmUgYXBwcm9wcmlhdGUgZmlndXJlIGxlZ2VuZHMuDQoNCklmIHVzaW5nIGZpZ3VyZXMgY3JlYXRlIGEgZmlndXJlcyBkaXJlY3RvcnkgaW4geW91ciByZXBvIGFuZCBtYWtlIHN1cmUgYWxsIHJlZmVyZW5jZXMgdG8gdGhlIGZpZ3VyZXMgYXJlIHJlbGF0aXZlIGluIHlvdXIgUm1hcmtkb3duIG5vdGVib29rLg0KDQoNClRoZSBtb3N0IGltcG9ydGFudCBhc3BlY3Qgb2YgdGhlIGFuYWx5c2lzIGlzIHJlbGF0aW5nIHlvdXIgcmVzdWx0cyBiYWNrIHRvIHRoZSBpbml0aWFsIGRhdGEgYW5kIHF1ZXN0aW9uLg0KDQoxLiBEbyB0aGUgZW5yaWNobWVudCByZXN1bHRzIHN1cHBvcnQgY29uY2x1c2lvbnMgb3IgbWVjaGFuaXNtIGRpc2N1c3NlZCBpbiB0aGUgb3JpZ2luYWwgcGFwZXI/IEhvdyBkbyB0aGVzZSByZXN1bHRzIGRpZmZlciBmcm9tIHRoZSByZXN1bHRzIHlvdSBnb3QgZnJvbSBBc3NpZ25tZW50ICMyIHRocmVzaG9sZGVkIG1ldGhvZHMuXCANCg0KVGhpcyBpcyBhIHF1b3RhdGlvbiB0YWtlbiBmcm9tIHRoZSBvcmlnaW5hbCBwYXBlciAiU0FSUy1Db1YtMiBpbmR1Y2VkIGEgc3Ryb25nIGFudGl2aXJhbCByZXNwb25zZSB3aXRoIHVwLXJlZ3VsYXRpb24gb2YgYW50aXZpcmFsIGZhY3RvcnMgc3VjaCBhcyBPQVMxLTMgYW5kIElGSVQxLTMgYW5kIFQgaGVscGVyIHR5cGUgMSAoVGgxKSBjaGVtb2tpbmVzIENYQ0w5LzEwLzExLCBhcyB3ZWxsIGFzIGEgcmVkdWN0aW9uIGluIHRyYW5zY3JpcHRpb24gb2Ygcmlib3NvbWFsIHByb3RlaW5zIiBbQGxpZWJlcm1hbjIwMjB2aXZvXS4gVGhleSBoYXZlIGZvdW5kIHVwLXJlZ3VsYXRpb24gaW4gbnVtYmVyIG9mIGdlbmVzLiBUaGUgbGFyZ2VzdCBjb2xsYXBzZWQgdGhlbWUgd2l0aCA3MjkgZ2VuZXMgdGhlIEdQQ1JTIFJob2RvcHNpbiBsaWdhbmQgaGFzIHR3byB2ZXJ5IGxhcmdlIHBhdGh3YXlzIG5hbWVkIHRoZSBHUENSIGxpZ2FuZCBiaW5kaW5nLCBhbmQgdGhlIENMQVNTIEEgMSAoUkhPRE9QU0lOLUxJS0UgUkVDRVBUT1JTKS4gQm90aCBvZiB0aGVzZSBnZW5lLXNldHMgaGF2ZSBhdCB0aGUgdG9wIG9mIHRoZWlyIGxlYWRpbmcgZWRnZSB0aGUgQ1hDTCAxMC8xMS8xMyBzaW1pbGFyIHRvIHRoZSBwYXBlciB3aGVyZSB0aGV5IGhhZCB1cC1yZWd1bGF0aW9uIGluIHRoZSBDWENMIDkvMTAvMTEuIEluIHRoaXMgc2Vuc2UgdGhlIGVucmljaG1lbnQgcmVzdWx0cyBzdXBwb3J0IGNvbmNsdXNpb25zIG1hZGUgaW4gdGhlIG9yaWdpbmFsIHBhcGVyLiBBbm90aGVyIGV4YW1wbGUgaXMgdGhlIGNoZW1va2luZSBtaWdyYXRpb24gY2hlbW90YXhpcy4gSW4gdGhpcyBtYWpvciB0aGVtZSB0aGVyZSBhcmUgZ2VuZS1zZXRzIGludm9sdmVkIGluIHBhdGh3YXlzIHN1Y2ggYXMgdGhlIHJlc3BvbnNlIHRvIHR5cGUgSUkgaW50ZXJmZXJvbiwgY2VsbHVsYXIgcmVzcG9uc2UgdG8gdHlwZSBJSSBpbnRlcmZlcm9uLCAuIEluIHRoZSBvcmlnaW5hbCBwYXBlciB0aGV5IG1lbnRpb24gdGhhdCBhcyB2aXJhbCBsb2FkIGluY3JlYXNlZCB0aGUgZXhwcmVzc2lvbiBvZiBpbnRlcmZlcm9uLXJlc3BvbnNpdmUgZ2VuZXMgd2VudCB1cC4gQm90aCBvZiB0aGUgdHdvIHRoZW1lcyBtZW50aW9uZWQgYXJlIHVwLXJlZ3VsYXRlZCBnZW5lLXNldHMuIEl0IHNlZW1zIHRoYXQgdGhlIGVucmljaG1lbnQgcmVzdWx0cyBzdXBwb3J0IHRoZSBjb25jbHVzaW9uIGluIHRoZSBvcmlnaW5hbCBwYXBlci4gXCANCkNvbXBhcmluZyBmcm9tIEEyIHRocmVzaG9sZCBtZXRob2RzIGluIHRoZSB1cHJlZ3VsYXRlZCBhbmFseXNpcyBmb3IgR08gdXNpbmcgZzpwcm9maWxlciB3ZSBhbHNvIGhhZCByZXN1bHRzIHN1Y2ggYXMgcmVzcG9uc2UgdG8gdHlwZSBJSSBpbnRlcmZlcm9uLCBhbmQgY2VsbHVsYXIgcmVzcG9uc2UgdG8gdHlwZSBJSSBpbnRlcmZlcm9uLiBIb3dldmVyIHdlIGRvIG5vdCBzZWUgYSBsb3Qgb2YgZ2VuZS1zZXRzIGluIHRoZSB1cC1yZWd1bGF0ZWQgc2VjdGlvbiBmb3IgY2hlbW9raW5lIHJlbGF0ZWQgcGF0aHdheXMuIFwgDQoNCkZvciBkb3duIHJlZ3VsYXRlZCBnZW5lLXNldHMgZm9yIG91ciBuZXR3b3JrIHJlc3VsdHMgZnJvbSBHU0VBIHNob3dzIGEgbWFqb3IgdGhlbWUgY2FsbGVkIHNycCBwcm90ZWluIHN5bnRoZXNpcy4gSW4gdGhpcyB3ZSBoYXZlIGdlbmVzZXRzIHN1Y2ggYXMgdGhlIGN5dG9wbGFzbWljIHRyYW5zbGF0aW9uLiBUaGlzIGdlbmUtc2V0IGlzIHRoZSBsYXJnZXN0IGdlbmUtc2V0IGluc2lkZSBzcnAgcHJvdGVpbiBzeW50aGVzaXMgYW5kIGl0IGlzIGFsc28gdGhlIHRvcCByZXN1bHQgZm9yIGRvd24gcmVndWxhdGVkIGdlbmVzIGdlbmUtc2V0IGZvciBnOnByb2ZpbGVyIHVzaW5nIEdPIGFubm90YXRpb24uIFRoZXJlIGFyZSBldmlkZW50IHNpbWlsYXJpdGllcyBidXQgbG9va2luZyBhdCB0aGUgcmVzdCBvZiB0aGUgZ3JhcGggZWFjaCBhbmFseXNpcyBnaXZlIHJlc3VsdHMgdGhhdCBlYWNoIG90aGVyIGRvIG5vdCBoYXZlLiBcIA0KDQoNCg0KMi4gQ2FuIHlvdSBmaW5kIGV2aWRlbmNlLCBpLmUuIHB1YmxpY2F0aW9ucywgdG8gc3VwcG9ydCBzb21lIG9mIHRoZSByZXN1bHRzIHRoYXQgeW91IHNlZS4gSG93IGRvZXMgdGhpcyBldmlkZW5jZSBzdXBwb3J0IHlvdXIgcmVzdWx0Pw0KSW4gYSBwYXBlciB0aGV5IHN0YXRlIHRoYXQgU0FSUy1Db1YtMiBpbmZlY3RlZCB0aHlyb2lkIGdsYW5kIGFjdGl2YXRlZCB0aGUgaW50ZXJmZXJvbiBwYXRod2F5cyBhbGlnbmluZyB3aXRoIG91ciByZXN1bHRzIGluIHRoZSB1cHJlZ3VsYXRpb24uIFtAaW50ZXJmZXJvbl0NCg0KDQpVc2luZyB5b3VyIG5ldHdvcmtzIGFuZCByZXN1bHRzIGZyb20gdGhlIHByZXZpb3VzIHNlY3Rpb24gYWRkIG9uZSBvZiB0aGUgZm9sbG93aW5nOg0KMS4gQWRkIGEgcG9zdCBhbmFseXNpcyB0byB5b3VyIG1haW4gbmV0d29yayB1c2luZyBzcGVjaWZpYyB0cmFuc2NyaXB0aW9uIGZhY3RvcnMsIG1pY3JvUk5BcyBvciBkcnVncy4gSW5jbHVkZSB0aGUgcmVhc29uIHdoeSB5b3UgY2hvc2UgdGhlIHNwZWNpZmljIG1pUnMsIFRGcyBvciBkcnVncyAoaS5lIHB1YmxpY2F0aW9ucyBpbmRpY2F0aW5nIHRoYXQgdGhleSBtaWdodCBiZSByZWxhdGVkIHRvIHlvdXIgbW9kZWwpLiBXaGF0IGRvZXMgdGhpcyBwb3N0IGFuYWx5c2lzIHNob3c/DQoyLCBDaG9vc2UgYSBzcGVjaWZpYyBwYXRod2F5IG9yIHRoZW1lIHRvIGludmVzdGlnYXRlIGluIG1vcmUgZGV0YWlsLiBXaHkgZGlkIHlvdSBjaG9vc2UgdGhpcyBwYXRod2F5IG9yIHRoZW1lPyBTaG93IHRoZSBwYXRod2F5IG9yIHRoZW1lIGFzIGEgZ2VuZSBuZXR3b3JrIG9yIGFzIGEgcGF0aHdheSBkaWFncmFtLiBBbm5vdGF0ZSB0aGUgbmV0d29yayBvciBwYXRod2F5IHdpdGggeW91ciBvcmlnaW5hbCBsb2cgZm9sZCBleHByZXNzaW9uIHZhbHVlcyBhbmQgcC12YWx1ZXMgdG8gc2hvdyBob3cgaXQgaXMgZWZmZWN0ZWQgaW4geW91ciBtb2RlbC4gKEhpbnQ6IGlmIHRoZSB0aGVtZSBvciBwYXRod2F5IGlzIG5vdCBmcm9tIGRhdGFiYXNlIHRoYXQgaGFzIGRldGFpbGVkIG1lY2hhbmlzdGljIGluZm9ybWF0aW9uIGxpa2UgUmVhY3RvbWUgeW91IGNhbiB1c2UgYXBwcyBsaWtlIEdlbmVNQU5JQSBvciBTdHJpbmcgdG8gYnVpbGQgdGhlIHRoZSBpbnRlcmFjdGlvbiBuZXR3b3JrLikNCjMuIFNvbWV0aW1lcyB0aGUgbW9zdCBpbnRlcmVzdGluZyBpbmZvcm1hdGlvbiBpcyB0aGUgZ2VuZSB0aGF0IGhhcyBubyBpbmZvcm1hdGlvbi4gSW4gdGhpcyB0eXBlIG9mIHBhdGh3YXkgYW5hbHlzaXMgd2UgY2FuIG9ubHkgZGlzY292ZXIgd2hhdCB3ZSBoYXZlIGFscmVhZHkgZGVzY3JpYmVkIHByZXZpb3VzbHkgaW4gdGhlIGxpdGVyYXR1cmUgb3IgcGF0aHdheSBkYXRhYmFzZXMuIE9mdGVuIHBhdGh3YXlzIGZvdW5kIGluIG9uZSBkaXNlYXNlIGFyZSBhcHBsaWNhYmxlIHRvIG90aGVyIGRpc2Vhc2VzIHNvIHRoaXMgdGVjaG5pcXVlIGNhbiBiZSB2ZXJ5IGhlbHBmdWwuIEl0IGlzIGltcG9ydGFudCB0byBoaWdobGlnaHQgYW55IGdlbmVzIHRoYXQgYXJlIHNpZ25pZmljYW50bHkgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGluIHlvdXIgbW9kZWwgYnV0IGFyZSBub3QgYW5ub3RhdGVkIHRvIGFueSBwYXRod2F5cy4gV2UgcmVmZXIgdG8gdGhpcyBzZXQgb2YgZ2VuZXMgYXMgdGhlIGRhcmsgbWF0dGVyLg0KSW5jbHVkZSBhIGhlYXRtYXAgb2YgYW55IHNpZ25pZmljYW50IGdlbmVzIHRoYXQgYXJlIG5vdCBhbm5vdGF0ZWQgdG8gYW55IG9mIHRoZSBwYXRod2F5cyByZXR1cm5lZCBpbiB0aGUgZW5yaWNobWVudCBhbmFseXNpcy4NCkluY2x1ZGUgYSBoZWF0bWFwIG9mIGFueSBzaWduaWZpY2FudCBnZW5lcyB0aGF0IGFyZSBub3QgYW5ub3RhdGVkIHRvIGFueSBwYXRod2F5cyBpbiBlbnRpcmUgc2V0IG9mIHBhdGh3YXlzIHVzZWQgZm9yIHRoZSBhbmFseXNpcy4NCg0KI1JlZmVyZW5jZXM=